#include "tcpserver.h"

Tcpserver::Tcpserver(/* args */)
{
    this->serverfd = -1;
    this->clientfd = -1;
}

Tcpserver::~Tcpserver()
{
    this->closeClientFD();
    this->closeServerFD();
}

bool Tcpserver::initServer(const unsigned short & port)
{
    // 判断serverfd是否为-1
    if(this->serverfd != -1)
    {
        return false;
    }

    // 1、创建服务端的socket
    this->serverfd = socket(AF_INET, SOCK_STREAM, 0);
    if (this->serverfd == -1)
    {
        return false;
    }

    // 2、把服务端用于通信的ip和端口绑定到socket上
    struct sockaddr_in serveraddr;   // 用于存放服务端ip和端口的数据结构
    memset(&serveraddr, 0, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;   // 指定ipv4
    serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);   // 服务器端任意网卡的ip都可用于通讯，服务器可能在不同网段拥有多个ip
    serveraddr.sin_port = htons(port);   // 指定端口
    this->port = port;
    // 绑定服务端的ip和端口
    int bindId = ::bind(this->serverfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
    if(bindId == -1)
    {
        ::close(this->serverfd);
        this->serverfd = -1;
        return false;
    }
     // 3、把socket设置为监听状态
    auto listenId = listen(this->serverfd, 5);
    if (listenId == -1)
    {
        ::close(this->serverfd);
        this->serverfd = -1;
        return false;
    } 
    return true;
}

bool Tcpserver::accept()
{
    struct sockaddr_in caddr;   // 客户端的地址
    socklen_t addrlen = sizeof(caddr);
    this->clientfd = ::accept(this->serverfd, (struct sockaddr *)&caddr, &addrlen);
    if (clientfd == -1)
    {
        return false;
    }
    this->clientIp = inet_ntoa(caddr.sin_addr);   // 将客户端的地址从大端序转为小端序字符串
    return true;
}

bool Tcpserver::send(const std::string & buffer)
{
    if (this->clientfd == -1)
    {
        return false;
    }
    auto retIndex = ::send(this->clientfd, buffer.data(), buffer.size(), 0);
    if (retIndex <= 0)
    {
        return false;
    }
    return true;
}

bool Tcpserver::recv(std::string & buffer, const size_t maxLen)
{

    buffer.clear();  //清空容器
    buffer.resize(maxLen);   // 设置容器的大小maxLen
    auto readNum = ::recv(this->clientfd, &buffer[0], buffer.size(), 0);  // 直接操作buffer的内存，一般不会直接操作string对象的内存，
                                                                        // 如果直接操作string对象的内存，1，不能越界,2，操作后手动设置数据大小
    if (readNum <= 0)  // -1失败，0 socket断开连接，>0成功接收到数据
    {
        buffer.clear();
        return false;
    }
    buffer.resize(readNum);   // 重新设置buffer的大小
    return true;

}

bool Tcpserver::closeServerFD()
{
    if (this->serverfd == -1)
    {
        return false;
    }
    ::close(this->serverfd);
    this->serverfd = -1;
    return true;
}

bool Tcpserver::closeClientFD()
{
    if (this->clientfd == -1)
    {
        return false;
    }
    ::close(this->clientfd);
    this->clientfd = -1;
    return true;
}

